//
//  RequestManager.swift
//  Chatup
//
//  Created by op on 2023/10/22.
//

import Alamofire
import Foundation
import Network
import StreamReader
import SwiftyJSON
import MobileCoreServices

class Reachability {
    static let shared = Reachability()
    private let reachability = NetworkReachabilityManager()
    var connected: Bool = true
    var type: String = ""
    private let queue = DispatchQueue(label: "reachability_queue")

    func startListener() {
        reachability?.startListening(onQueue: queue, onUpdatePerforming: { [weak self] status in
            switch status {
            case let .reachable(type):
                self?.connected = true
                self?.type = "\(type)"
            default:
                self?.connected = false
            }
        })
    }

    func stopListener() {
        reachability?.stopListening()
    }
}

struct ResponseModel {
    var code: Int
    var message: String
    var data: JSON

    static func toModel(_ json: JSON) -> ResponseModel {
        let code = json["code"].intValue
        let message = json["message"].stringValue
        let data = json["data"]
        return ResponseModel(code: code, message: message, data: data)
    }
}

class HttpRequestInterceptor: RequestInterceptor {
    private let HEADER_UA = "User-Agent"
    private let HEADER_CONTENT_TYPE = "Content-Type"
    func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
        let request = sign(request: urlRequest)
        completion(.success(request))
    }

    func adapt(_ urlRequest: URLRequest, using state: RequestAdapter, completion: @escaping (Result<URLRequest, Error>) -> Void) {
        let request = sign(request: urlRequest)
        completion(.success(request))
    }

    func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
        completion(.retry)
    }

    func sign(request: URLRequest) -> URLRequest {
        guard request.url?.absoluteString != nil else {
            return request
        }

        var retRequest = request
        retRequest.timeoutInterval = 10
        retRequest.headers = getHeader()
        return retRequest
    }

    func getHeader() -> HTTPHeaders {
        var headers = HTTPHeaders()
        headers.add(name: HEADER_CONTENT_TYPE, value: "application/json")
        headers.add(name: "accept", value: "text/event-stream, application/json, text/event-stream")

        return headers
    }
}

public enum HttpErrorType: Int {
    case no_response = -999
}

typealias onSuccess = (JSON?, Int?) -> Void
typealias onSuccess2 = (Data?, Int?) -> Void

typealias onFail = (HttpErrorType, Int?, String?) -> Void
typealias onReading = (String) -> Void
private let response_code_success = 200
private let statu_code_success = 0
private let msg_network_error = "Oops, connection trouble."

class RequestManager {
    private var sessionManager: Session?
    private let interceptor = HttpRequestInterceptor()

    init() {
        let config = URLSessionConfiguration.default
        config.timeoutIntervalForRequest = 10
        config.headers = interceptor.getHeader()
        config.multipathServiceType = .handover
        sessionManager = Session(configuration: config, delegate: SessionDelegate())
    }

    func postWithStream<Parameters: Encodable>(_ url: String, params: Parameters, success: @escaping onSuccess, fail: @escaping onFail, reading: @escaping onReading = { _ in }) {
        guard hasNetwork(fail: fail) else { return }

        sessionManager?.streamRequest(url, method: .post, parameters: params, encoder: JSONParameterEncoder.default, headers: interceptor.getHeader()).responseStream(stream: { [weak self] stream in
            guard let self = self else { return }
            self.handleResultWithStreamLine(stream, fail: fail, success: success, reading: reading)
            
            
        })
    }

    func getWith(_ urlStr: String, success: @escaping onSuccess2, fail: @escaping onFail) {
        if let url = URL(string: urlStr) {
            // 创建 URLSession
            let session = URLSession.shared

            // 创建数据任务
            let dataTask = session.dataTask(with: url) { data, _, error in
                if let error = error {
                    print("Error: \(error)")
                    self.handleFail(fail, type: .no_response, errorCode: HttpErrorType.no_response.rawValue, errorMsg: "\(error)")
                } else if let data = data {
                    // 将数据解析成 JSON
                    self.handleSuccess2(success, json: data)
                }
            }

            // 启动任务
            dataTask.resume()
        }
    }
    
    func getWithUrl(_ url: URL, success: @escaping onSuccess2, fail: @escaping onFail) {
        // 创建 URLSession
        let session = URLSession.shared

        // 创建数据任务
        let dataTask = session.dataTask(with: url) { data, _, error in
            if let error = error {
                print("Error: \(error)")
                self.handleFail(fail, type: .no_response, errorCode: HttpErrorType.no_response.rawValue, errorMsg: "\(error)")
            } else if let data = data {
                // 将数据解析成 JSON
                self.handleSuccess2(success, json: data)
            }
        }

        // 启动任务
        dataTask.resume()
    }
    func getWith1(_ url: String, success: @escaping onSuccess, fail: @escaping onFail) {
        if let url = URL(string: url) {
            // 创建 URLSession
            let session = URLSession.shared

            // 创建数据任务
            let dataTask = session.dataTask(with: url) { data, _, error in
                if let error = error {
                    print("Error: \(error)")
                    self.handleFail(fail, type: .no_response, errorCode: HttpErrorType.no_response.rawValue, errorMsg: "\(error)")
                } else if let data = data {
                    // 将数据解析成 JSON
                    self.handleSuccess(success, json: JSON(data))
                }
            }

            // 启动任务
            dataTask.resume()
        }
    }
    func postWith(_ url: String, fileURL: URL,endpointUserId :String, completion: @escaping (Result<Data, Error>) -> Void) {
        guard let url = URL(string: url) else {
                completion(.failure(URLError(.badURL)))
                return
            }

            var request = URLRequest(url: url)
            request.httpMethod = "POST"
            let boundary = "Boundary-\(UUID().uuidString)"
            request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

            var body = Data()

            // 添加文件
            body.append("--\(boundary)\r\n".data(using: .utf8)!)
            body.append("Content-Disposition: form-data; name=\"file\"; filename=\"\(fileURL.lastPathComponent)\"\r\n".data(using: .utf8)!)
            body.append("Content-Type: \(fileURL.mimeType)\r\n\r\n".data(using: .utf8)!)
            if let fileData = try? Data(contentsOf: fileURL) {
                body.append(fileData)
            }
            body.append("\r\n".data(using: .utf8)!)

            // 添加字符串参数
            body.append("--\(boundary)\r\n".data(using: .utf8)!)
            body.append("Content-Disposition: form-data; name=\"ep_user_id\"\r\n\r\n".data(using: .utf8)!)
            body.append(endpointUserId.data(using: .utf8)!)
            body.append("\r\n".data(using: .utf8)!)

            // 结束标记
            body.append("--\(boundary)--\r\n".data(using: .utf8)!)


            let task = URLSession.shared.uploadTask(with: request, from: body) { data, response, error in
                if let error = error {
                    print("Upload error: \(error.localizedDescription)")
                    return
                }
                let httpResponse = response as? HTTPURLResponse
                if httpResponse?.statusCode == 200 {
                    completion(.success(data!))
                } else {
                    completion(.failure(URLError(.cannotDecodeContentData)))
                }
            }
            task.resume()
    }
    
    

    /// 中断所有请求
    func cancelAllRequests() {
        if let sessionManager = sessionManager {
            sessionManager.cancelAllRequests()
        }
    }
    
    func postWithJson(_ url: String, parameters :[String : Any], completion: @escaping (Result<Data, Error>) -> Void){

        let headers = ["content-type": "application/json"]
        
        do {
            let postData = try JSONSerialization.data(withJSONObject: parameters, options: [])
            let request = NSMutableURLRequest(url: NSURL(string: url)! as URL,
                                                    cachePolicy: .useProtocolCachePolicy,
                                                timeoutInterval: 60.0)
            request.httpMethod = "POST"
            request.allHTTPHeaderFields = headers
            request.httpBody = postData as Data
            let configuration = URLSessionConfiguration.default
            configuration.timeoutIntervalForRequest = 60 // 请求超时时间（秒）
            configuration.timeoutIntervalForResource = 60 // 资源超时时间（秒）
            let session = URLSession(configuration: configuration)
            let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
              if (error != nil) {
                  completion(.failure(error!))
              } else {
                let httpResponse = response as? HTTPURLResponse
                  if httpResponse?.statusCode == 200 {
                      completion(.success(data!))
                  } else {
                      completion(.failure(URLError(.cannotDecodeContentData)))
                  }
              }
            })

            dataTask.resume()
            
        } catch { }
 
    }
    
}

extension RequestManager {
    private func handleFail(_ fail: @escaping onFail, type: HttpErrorType, errorCode: Int, errorMsg: String) {
        DispatchQueue.main.async {
            fail(type, errorCode, errorMsg)
        }
    }

    private func handleSuccess(_ success: @escaping onSuccess, json: JSON?, code: Int? = statu_code_success) {
        DispatchQueue.main.async {
            success(json, code)
        }
    }

    private func handleSuccess2(_ success: @escaping onSuccess2, json: Data?, code: Int? = statu_code_success) {
        DispatchQueue.main.async {
            success(json, code)
        }
    }

    private func handleReading(_ reading: @escaping onReading, content: String) {
        DispatchQueue.main.async {
            reading(content)
        }
    }

    // 以字节流的方式逐行读取
    private func handleResultWithStreamLine(_ response: DataStreamRequest.Stream<Data, Never>, fail: @escaping onFail, success: @escaping onSuccess, reading: @escaping onReading) {
        var result = ""
        let isFinish = false
        if let data = response.value {
            let reader = DataReader(data: data)
            do {
                while let (line, _) = try? reader.readLine() {
                    guard let lineStr = String(data: line, encoding: .utf8) else {
                        handleSuccess(success, json: nil, code: 201)
                        return
                    }
//            print("handleResultWithStreamLine-\(lineStr)-end")
                    let lineResult = lineStr
                    result.append(lineResult)
                    if let jsonData = lineResult.data(using: .utf8) {
                        do {
                            if let dictionary = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] {
                                if let c = dictionary["code"] as? Int{
                                    if c == -1 || c == -2{
                                        return handleFail(fail, type: .no_response, errorCode: c, errorMsg: dictionary["msg"] as? String ?? "")
                                    
                                    }else{
                                        handleReading(reading, content: lineResult)
                                    }
                                }else{
                                    handleReading(reading, content: lineResult)
                                }
                            }
                        } catch {
                            handleReading(reading, content: lineResult)
                        }
                    }
                    
                }
            }
            if isFinish {
                handleSuccess(success, json: JSON(result))
            }
        }
        if isFinish == false {
            switch response.event {
            case let .complete(completion):
                let c = completion.response?.statusCode
                guard c != nil else {
                    return handleFail(fail, type: .no_response, errorCode: c ?? -1, errorMsg: msg_network_error)
                }
                handleSuccess(success, json: JSON(result), code: c)
            default:
                break
            }
        }
    }

    // 网络是否可用
    private func hasNetwork(fail: @escaping onFail) -> Bool {
        let connected = Reachability.shared.connected
        return connected
    }
}

extension RequestManager {
    public static let shared: RequestManager = .init()
}

extension URL {
    var mimeType: String {
        let pathExtension = self.pathExtension
        if let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension as CFString, nil)?.takeRetainedValue() {
            if let mimeType = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?.takeRetainedValue() {
                return mimeType as String
            }
        }
        return "application/octet-stream"
    }
}
